-
-
Notifications
You must be signed in to change notification settings - Fork 546
feat: add HTTP/HTTPS proxy support for all API traffic #301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
- Add fetchWithProxy() utility using https-proxy-agent - Thread proxyUrl through all fetch call sites (token refresh, project context, quota, search) - Save proxy URL from ANTIGRAVITY_LOGIN_PROXY env during login - Store proxyUrl per-account in antigravity-accounts.json - Add docs/PROXY.md with configuration guide - Update README with proxy quick start section Supports: http://host:port, http://user:pass@host:port, https://host:port Note: SOCKS5 proxies are NOT supported
WalkthroughAdds full proxy support: new src/plugin/proxy.ts providing ProxyAgent caching, sanitization, dispose, and fetchWithProxy; wires proxyUrl through OAuth, token refresh, project onboarding/load, quota checks, search, account persistence, and content generation. AccountMetadataV3 and ManagedAccount gain optional proxyUrl persisted from ANTIGRAVITY_LOGIN_PROXY. Adds undici dependency and new tests in src/plugin/proxy.test.ts. README.md and docs/PROXY.md receive proxy usage documentation. Multiple function signatures updated to accept an optional proxyUrl. Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. No actionable comments were generated in the recent review. 🎉 📜 Recent review detailsConfiguration used: Repository UI Review profile: CHILL Plan: Pro Cache: Disabled due to data retention organization setting Knowledge base: Disabled due to data retention organization setting 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
✏️ Tip: You can disable this entire section by setting Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
To use Codex here, create an environment for this repo. |
Greptile OverviewGreptile SummaryThis PR introduces per-account HTTP/HTTPS proxy support by adding a From the code changes reviewed, the new proxy plumbing generally preserves existing behavior when Confidence Score: 4/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant CLI as CLI
participant Plugin
participant Storage
participant OAuth
participant API
User->>CLI: Login
CLI->>Plugin: OAuth start
Plugin->>OAuth: token exchange (proxied fetch)
OAuth-->>Plugin: tokens
Plugin->>Storage: save account metadata (includes proxy setting)
User->>CLI: Make request
CLI->>Plugin: fetch()
Plugin->>Storage: load account metadata
Plugin->>OAuth: refresh token if needed (proxied fetch)
OAuth-->>Plugin: access token
Plugin->>API: API call (proxied fetch)
API-->>Plugin: response
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5 files reviewed, 1 comment
Additional Comments (1)
Prompt To Fix With AIThis is a comment left during a code review.
Path: src/plugin/accounts.ts
Line: 762:775
Comment:
`proxyUrl` is missing from the account mapping in `saveToDisk()`. The proxy configuration will not persist across application restarts, even though it's saved during login in `plugin.ts:345`. Add `proxyUrl: a.proxyUrl` to the mapped account object.
How can I resolve this? If you propose a fix, please make it concise. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8f2fa57280
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
proxyUrl was missing from saveToDisk() mapping and constructor hydration, causing proxy config to be lost on restart and all API calls to bypass proxy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
4 files reviewed, 2 comments
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Signed-off-by: Aaron Sewall <aaronsewall@gmail.com>
Request objects were accepted but properties (method, headers, body) were silently lost. All call sites pass strings, so narrowing the type prevents future misuse. Removed test for Request input since it's no longer valid.
Resolve conflicts to keep both proxy support and new quota caching features. Added proxyUrl parameter to fetchGeminiCliQuota for parallel quota fetching.
Signed-off-by: Aaron Sewall <aaronsewall@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
6 files reviewed, 1 comment
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Signed-off-by: Aaron Sewall <aaronsewall@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
7 files reviewed, 1 comment
Additional Comments (1)
Both Add Prompt To Fix With AIThis is a comment left during a code review.
Path: src/plugin/quota.ts
Line: 329:336
Comment:
proxy not used for token refresh and project context during quota checks
Both `refreshAccessToken()` and `ensureProjectContext()` are missing the `account.proxyUrl` parameter. This means quota checks will bypass the configured proxy for authentication and project discovery, even though the actual quota API calls (lines 345-347) correctly use the proxy.
Add `account.proxyUrl` as the 4th parameter to `refreshAccessToken()` on line 329, and as the 2nd parameter to `ensureProjectContext()` on line 336.
How can I resolve this? If you propose a fix, please make it concise. |
Signed-off-by: Aaron Sewall <aaronsewall@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5 files reviewed, 4 comments
- Add MAX_AGENT_CACHE_SIZE (50) with LRU eviction to prevent unbounded growth - Add disposeProxyAgent() for explicit cleanup when accounts are removed - Fix proxyUrl clearing logic: use explicit undefined check instead of ?? (allows removing proxy by setting empty string, not treated as falsy) - Pass account.proxyUrl to refreshAccessToken() and ensureProjectContext() in quota checks to ensure proxy is used for all auth operations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
7 files reviewed, 1 comment
| refreshToken: parts.refreshToken, | ||
| projectId: parts.projectId ?? existing.projectId, | ||
| managedProjectId: parts.managedProjectId ?? existing.managedProjectId, | ||
| proxyUrl: proxyUrl !== undefined ? proxyUrl : existing.proxyUrl, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
proxy cannot be cleared once set - undefined falls back to existing proxy
if user logs in without ANTIGRAVITY_LOGIN_PROXY after previously setting a proxy, the old proxy persists. empty string ("") would also be falsy and fall back.
to enable proxy clearing, distinguish between "not provided" vs "explicitly cleared":
| proxyUrl: proxyUrl !== undefined ? proxyUrl : existing.proxyUrl, | |
| proxyUrl: proxyUrl !== undefined ? proxyUrl : existing.proxyUrl, |
could become:
// Use null to explicitly clear proxy
proxyUrl: proxyUrl !== undefined ? (proxyUrl || null) : existing.proxyUrl,
then users could clear with ANTIGRAVITY_LOGIN_PROXY="" opencode auth login
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugin.ts
Line: 423:423
Comment:
proxy cannot be cleared once set - `undefined` falls back to existing proxy
if user logs in without `ANTIGRAVITY_LOGIN_PROXY` after previously setting a proxy, the old proxy persists. empty string (`""`) would also be falsy and fall back.
to enable proxy clearing, distinguish between "not provided" vs "explicitly cleared":
```suggestion
proxyUrl: proxyUrl !== undefined ? proxyUrl : existing.proxyUrl,
```
could become:
```
// Use null to explicitly clear proxy
proxyUrl: proxyUrl !== undefined ? (proxyUrl || null) : existing.proxyUrl,
```
then users could clear with `ANTIGRAVITY_LOGIN_PROXY="" opencode auth login`
How can I resolve this? If you propose a fix, please make it concise.|
@aaronsewall do you intend on moving this forward? |
…proxy Merge origin/dev which adds account verification, config updater, quota fallback tests, refresh queue, model resolver updates, and CLI/UI improvements. Conflict resolution: - plugin.ts: combined saveAccountsReplace + AccountMetadataV3 imports - storage.ts: kept both proxyUrl and verification fields on AccountMetadataV3 Proxy coverage fixes: - verifyAccountAccess: use fetchWithProxy for Antigravity API probe - verifyAccountAccess: pass proxyUrl to refreshAccessToken - Google Search tool: resolve account before token refresh for proxyUrl - ProactiveRefreshQueue: pass account.proxyUrl to refreshAccessToken
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
15 files reviewed, 1 comment
Additional Comments (1)
Prompt To Fix With AIThis is a comment left during a code review.
Path: src/plugin.ts
Line: 402:406
Comment:
**Proxy breaks warmup fetch**
`fetchWithProxy` only accepts `string | URL`, but later this file calls it with `resolvedUrl` which is not defined in this scope (the original code used `fetch(prepared.request, prepared.init)`). As written, this should fail to compile or will reference an undefined variable at runtime. This needs to be updated to pass the same request URL that was previously used (e.g. `prepared.request`), and ensure the argument type matches `fetchWithProxy`.
How can I resolve this? If you propose a fix, please make it concise. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/plugin/accounts.ts (1)
142-166:⚠️ Potential issue | 🟠 MajorPropagate
proxyUrlinto quota-refresh metadata.
checkAccountsQuota()now honorsaccount.proxyUrl, butAccountManager.getAccountsForQuotaCheck()still strips it, so background quota refresh can bypass the proxy. That breaks the “all traffic via proxy” guarantee.🔧 Proposed fix
getAccountsForQuotaCheck(): AccountMetadataV3[] { return this.accounts.map((a) => ({ email: a.email, refreshToken: a.parts.refreshToken, projectId: a.parts.projectId, managedProjectId: a.parts.managedProjectId, + proxyUrl: a.proxyUrl, addedAt: a.addedAt, lastUsed: a.lastUsed, enabled: a.enabled, })); }
🤖 Fix all issues with AI agents
In `@docs/PROXY.md`:
- Around line 112-126: The fenced code blocks containing the error examples lack
language identifiers and trigger MD040; update the two blocks that include the
exact strings "Error: Failed to create proxy agent for http://proxy:8080:
connect ECONNREFUSED" and "Error: Invalid proxy URL format:
http://***:***@:invalid" to use a language fence (e.g., ```text) so each fenced
block starts with ```text and ends with ``` to satisfy markdownlint.
🧹 Nitpick comments (6)
src/plugin/proxy.ts (3)
24-40: Comment says "LRU eviction" but this is actually FIFO.The cache uses
Mapinsertion order for eviction (oldest-inserted entries are removed first), but a re-used agent (cache hit on line 58) is never moved to the end of the map. True LRU would re-insert on access. With a max of 50 and typical usage of 1–5 proxies this is functionally fine, but the comment is misleading.
77-94: Mixed static and dynamic import ofundici.
ProxyAgentis statically imported at line 1 (always loaded), whilefetchis dynamically imported at line 88. If the intent of the dynamic import is to avoid loading undici when no proxy is configured, the static import on line 1 defeats that purpose. Consider making both imports dynamic, or both static for consistency.If you want both to be static (simpler):
-import { ProxyAgent } from 'undici'; +import { ProxyAgent, fetch as undiciFetch } from 'undici';Then in
fetchWithProxy, remove the dynamic import:- const { fetch: undiciFetch } = await import('undici');
88-93: Type incompatibility between globalRequestInitand undici'sRequestInitis suppressed via@ts-ignore.The
initparameter is typed as the globalRequestInit, but undici'sfetchexpects its ownRequestInit(fromundici). Properties likesignal,body, andheadershave subtly different types. The@ts-ignore+as unknowncast hides potential runtime issues. This works today for the simple cases in this PR (plain objects withmethod,headers,body,signal), but could break if callers pass more exotic RequestInit properties.Consider typing
initas a narrower interface with only the properties actually used, or importing undici'sRequestInitand using a union type.src/plugin/proxy.test.ts (2)
16-22: Agent cache leaks between tests, making test order significant.Since
agentCacheis module-private and never cleared between tests, agents created in earlier tests persist. Each test works around this by using unique URLs, but this is fragile — adding a test that reuses a URL from another test will produce confusing failures.Consider exporting a
clearAgentCache()test helper (or usingresetModulesinbeforeEach) to ensure isolation.
92-114: Test coverage gaps for proxy utilities.The
fetchWithProxytests cover the happy paths, but there's no coverage for:
disposeProxyAgent(exported, untested)- Unsupported protocol rejection (e.g.,
socks5://...)- LRU/FIFO eviction when cache exceeds
MAX_AGENT_CACHE_SIZEfetchWithProxywith aURLobject as input (the.hrefbranch on line 90 ofproxy.ts)These aren't blockers but would strengthen confidence in the module.
src/antigravity/oauth.ts (1)
119-135: Passingundefinedas positional placeholder fortimeoutMsis a code smell.
fetchWithTimeoutnow has two trailing optional parameters (timeoutMs,proxyUrl), forcing callers to passundefinedexplicitly to reach the proxy parameter (lines 165, 234, 252). Consider using an options object for the optional parameters.♻️ Suggested refactor
+interface FetchWithTimeoutOptions extends RequestInit { + timeoutMs?: number; + proxyUrl?: string; +} async function fetchWithTimeout( url: string, - options: RequestInit, - timeoutMs = FETCH_TIMEOUT_MS, - proxyUrl?: string, + options: FetchWithTimeoutOptions, ): Promise<Response> { + const { timeoutMs = FETCH_TIMEOUT_MS, proxyUrl, ...fetchOptions } = options; const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), timeoutMs); try { if (proxyUrl) { - return await fetchWithProxy(url, { ...options, signal: controller.signal }, proxyUrl); + return await fetchWithProxy(url, { ...fetchOptions, signal: controller.signal }, proxyUrl); } - return await fetch(url, { ...options, signal: controller.signal }); + return await fetch(url, { ...fetchOptions, signal: controller.signal }); } finally { clearTimeout(timeout); } }
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (14)
README.mddocs/PROXY.mdpackage.jsonsrc/antigravity/oauth.tssrc/plugin.tssrc/plugin/accounts.tssrc/plugin/project.tssrc/plugin/proxy.test.tssrc/plugin/proxy.tssrc/plugin/quota.tssrc/plugin/refresh-queue.tssrc/plugin/search.tssrc/plugin/storage.tssrc/plugin/token.ts
🧰 Additional context used
🧬 Code graph analysis (6)
src/plugin/token.ts (2)
src/plugin/proxy.ts (1)
fetchWithProxy(77-94)src/constants.ts (2)
ANTIGRAVITY_CLIENT_ID(4-4)ANTIGRAVITY_CLIENT_SECRET(9-9)
src/plugin/refresh-queue.ts (1)
src/plugin/token.ts (1)
refreshAccessToken(86-175)
src/plugin/search.ts (1)
src/plugin/proxy.ts (1)
fetchWithProxy(77-94)
src/antigravity/oauth.ts (1)
src/plugin/proxy.ts (1)
fetchWithProxy(77-94)
src/plugin/quota.ts (3)
src/plugin/proxy.ts (1)
fetchWithProxy(77-94)src/plugin/token.ts (1)
refreshAccessToken(86-175)src/plugin/project.ts (1)
ensureProjectContext(230-326)
src/plugin/proxy.test.ts (1)
src/plugin/proxy.ts (2)
getProxyAgent(42-75)fetchWithProxy(77-94)
🪛 markdownlint-cli2 (0.20.0)
docs/PROXY.md
[warning] 112-112: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 124-124: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (19)
package.json (1)
64-64: LGTM —undicidependency addition is appropriate.ProxyAgent isn't available through Node's built-in global fetch, so the explicit dependency is justified. The
^6.23.0range is compatible with thenode >= 20engine requirement.README.md (1)
263-299: LGTM — Proxy documentation section is clear and well-structured.Covers the key scenarios (env var setup, supported formats, security warning). The link to
docs/PROXY.mdfor advanced configuration is a good approach.src/antigravity/oauth.ts (2)
137-165: LGTM — proxy threading throughfetchProjectIDis correct.The env var read is appropriate here since this runs during the login flow before a persisted account exists.
208-254: LGTM — proxy threading throughexchangeAntigravityis correct.Same login-time env var usage pattern. Token exchange and userinfo fetch both correctly route through the proxy.
src/plugin/refresh-queue.ts (1)
227-227: LGTM — correctly passes per-account proxy URL to token refresh.src/plugin/storage.ts (1)
196-196: LGTM —proxyUrladdition toAccountMetadataV3is clean.The optional field integrates naturally with the existing merge logic (spread in
mergeAccountStorage) and migration paths (V2→V3 won't set it, which is correct for legacy accounts).src/plugin/accounts.ts (2)
378-383: LGTM: proxyUrl is hydrated from storage.Cleanly carries per-account proxy settings into the in-memory model.
1001-1016: LGTM: proxyUrl is persisted.Including proxyUrl in AccountStorage keeps behavior consistent across restarts.
src/plugin/token.ts (1)
6-6: Proxy-aware token refresh looks good.Cleanly threads
proxyUrland keeps existing error handling intact.Also applies to: 86-114
docs/PROXY.md (1)
1-106: Docs look solid and comprehensive.Covers login proxy, manual config, supported formats, and troubleshooting clearly.
src/plugin/search.ts (1)
17-17: LGTM: search requests are now proxy-aware.Signature and call-site changes are consistent and preserve existing behavior when unset.
Also applies to: 224-295
src/plugin/quota.ts (2)
7-7: LGTM: quota fetches are proxy-aware.fetchWithTimeout + proxyUrl propagation is clean and keeps timeouts intact.
Also applies to: 176-205, 219-242
327-348: LGTM: quota checks now threadaccount.proxyUrl.Consistent with the per-account proxy model.
src/plugin/project.ts (1)
9-9: LGTM: project context flows now respect proxyUrl.Consistent proxy threading across load, onboard, and ensure context.
Also applies to: 122-152, 172-200, 230-286
src/plugin.ts (5)
34-34: LGTM: verification flow is proxy-aware end to end.Proxy is passed through refresh and probe fetches cleanly.
Also applies to: 43-43, 438-514
757-835: LGTM: login proxy is persisted per account.Clear propagation from environment into new/updated account records.
1356-1386: LGTM: google_search now threads proxyUrl.Early account resolution makes proxy usage consistent with token refresh.
1715-1715: LGTM: proxy wiring in main request path.Token refresh, project context, warmup, and content fetches all respect per-account proxy.
Also applies to: 1789-1789, 1855-1860, 2017-2018
3151-3152: LGTM: proxyUrl preserved on account refresh updates.Ensures refreshed accounts keep their proxy association.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
Yes, just pushed updates. I'll respond to PR feedback as it comes in. It's been ready a few times. |
|
Looking forward to using this live rather than a fork I'm itterating on what I am calling the the "Silent Jailer" Protocol: Transparent Proxy Sandboxing |
no need to fix all the pr comments, sometimes these bots are wrong :) But if you could have a look at the conflicts I could merge it for the next release |
Supports: http://host:port, http://user:pass@host:port, https://host:port
Note: SOCKS5 proxies are NOT supported